﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics.Contracts;

namespace System.Linq.Expressions
{
	internal sealed class ExchangeExpressionVisitor : ExpressionVisitor
	{

		public ExchangeExpressionVisitor( Expression lookFor, Expression changeBy )
		{
			Contract.Requires<ArgumentNullException>( lookFor != null, "lookFor" );
			Contract.Requires<ArgumentNullException>( changeBy != null, "changeBy" );

			this.LookFor = lookFor;
			this.ChangeBy = changeBy;
		}


		public Expression LookFor
		{ get; private set; }

		public Expression ChangeBy
		{ get; private set; }


		public override Expression Visit( Expression node )
		{
			if ( node != null
				&& node.Equals( this.LookFor ) )
				return this.ChangeBy;
			else
				return base.Visit( node );
		}
	}


	public static class ExchangeExtensions
	{

		public static TExpression Replace<TExpression>( this TExpression exp, Expression lookFor, Expression replaceBy )
			where TExpression : Expression
		{
			if ( exp != null )
			{
				var replacer = new ExchangeExpressionVisitor( lookFor, replaceBy );
				return replacer.VisitAndConvert<TExpression>( exp, String.Empty );
			}
			else
				return null;
		}
	}
}
